package com.zhijian.warehouse.manage.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.format.FastDateFormat;
import com.zhijian.util.BeanUtil;
import com.zhijian.util.page.Page;
import com.zhijian.warehouse.manage.dao.StoreStockRecordMapper;
import com.zhijian.warehouse.manage.entity.dto.stock.StockActionDto;
import com.zhijian.warehouse.manage.entity.dto.stock.StockStorageDto;
import com.zhijian.warehouse.manage.entity.po.Store;
import com.zhijian.warehouse.manage.entity.po.StoreLock;
import com.zhijian.warehouse.manage.entity.po.StoreStockRecord;
import com.zhijian.warehouse.manage.entity.vo.request.*;
import com.zhijian.warehouse.manage.entity.vo.response.StoreLockVo;
import com.zhijian.warehouse.manage.entity.vo.response.StoreStockRecordProductVo;
import com.zhijian.warehouse.manage.entity.vo.response.StoreStockRecordVo;
import com.zhijian.warehouse.manage.entity.vo.response.StoreVo;
import com.zhijian.warehouse.manage.enums.CodingEnum;
import com.zhijian.warehouse.manage.enums.StockActionEnum;
import com.zhijian.warehouse.manage.enums.StoreEnum;
import com.zhijian.warehouse.manage.service.StoreLockService;
import com.zhijian.warehouse.manage.service.StoreService;
import com.zhijian.warehouse.manage.service.StoreStockRecordProductService;
import com.zhijian.warehouse.manage.service.StoreStockRecordService;
import com.zhijian.warehouse.manage.util.AssertCommonUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
 * 盘点记录业务处理层
 *
 * @author auto
 * @version: 1.0
 * @date 2024-10-27 13:46:26
 */
@Slf4j
@Service
public class StoreStockRecordServiceImpl implements StoreStockRecordService {

    @Autowired
    private StoreStockRecordMapper mapper;

    @Autowired
    private StoreService storeService;

    @Autowired
    private StoreStockRecordProductService storeStockRecordProductService;

    @Autowired
    private StoreLockService storeLockService;

    @Override
    public StoreStockRecord selectById(Long id) {
        return mapper.selectByPrimaryKey(id);
    }

    @Override
    public StoreStockRecordVo selectVoById(Long id) {
        StoreStockRecordVo storeStockRecordVo = mapper.selectVoById(id);
        if (Objects.isNull(storeStockRecordVo)) {
            return null;
        }
        //产品
        List<StoreStockRecordProductVo> storeStockRecordProductVos = storeStockRecordProductService.selectList(StoreStockRecordProductSearchVo.builder()
                .storeStockRecordId(id)
                .build());
        storeStockRecordVo.setStoreStockRecordProductList(storeStockRecordProductVos);
        storeStockRecordVo.setAllProduct(storeStockRecordProductVos.size());
        //重新查询产品数
        storeStockRecordProductVos.forEach(vo -> {
            if (BeanUtil.isEmpty(vo.getStoreCount())) {
                StoreVo storeVo = storeService.selectOne(StoreSearchVo.builder()
                        .warehouseId(storeStockRecordVo.getWarehouseId())
                        .productId(vo.getProductId())
                        .warehouseLocationId(vo.getWarehouseLocationId())
                        .build());
                if (storeVo != null) {
                    vo.setStoreCount(storeVo.getProductCount());
                    vo.setDeficitNumber(vo.getStockCount() == null ? null : vo.getStockCount().subtract(vo.getStoreCount()));
                }
            }
            if (vo.getStoreCount() != null) {
                vo.setDeficitNumber(vo.getStockCount() == null ? null : vo.getStockCount().subtract(vo.getStoreCount()));
            }
        });
        AtomicInteger lossCount = new AtomicInteger();
        AtomicInteger profitCount = new AtomicInteger();
        AtomicInteger panFlatCount = new AtomicInteger();
        storeStockRecordProductVos.forEach(vo -> {
            BigDecimal stockCount = vo.getStockCount();
            if (BeanUtil.isNotEmpty(stockCount) && BeanUtil.isNotEmpty(vo.getStoreCount())) {
                BigDecimal subtract = stockCount.subtract(vo.getStoreCount());
                if (subtract.compareTo(BigDecimal.ZERO) < 0) {
                    lossCount.getAndIncrement();
                    vo.setLossesProductCount(subtract.abs());
                } else if (subtract.compareTo(BigDecimal.ZERO) > 0) {
                    profitCount.getAndIncrement();
                    vo.setProfitProductCount(subtract);
                } else if (stockCount.compareTo(BigDecimal.ZERO) == 0)
                    panFlatCount.getAndIncrement();
            }
        });
        storeStockRecordVo.setLossesProductCount(lossCount.get());
        storeStockRecordVo.setProfitProductCount(profitCount.get());
        storeStockRecordVo.setStockProductCount(panFlatCount.get());
        return storeStockRecordVo;
    }

    @Override
    @Transactional
    public void deleteById(Long id) {
        AssertCommonUtil.notNull(id, "选择数据不能为空");
        StoreStockRecord storeStockRecord = this.selectById(id);
        AssertCommonUtil.notNull(storeStockRecord, "选择数据不存在");
        //仅草稿和已驳回可删除
        if (!Objects.equals(StoreEnum.StatusEnum.DRAFT.getCode(), (int) storeStockRecord.getStatus()) && !Objects.equals(StoreEnum.StatusEnum.REJECT.getCode(), (int) storeStockRecord.getStatus())) {
            AssertCommonUtil.notNull(null, "非草稿状态和驳回状态不允许删除");
        }
        storeStockRecordProductService.deleteByCondition(StoreStockRecordProductSearchVo.builder()
                .storeStockRecordId(id)
                .build());
        mapper.deleteByPrimaryKey(id);
        // 检查是否需要解锁仓库
        if (BeanUtil.isNotEmpty(storeStockRecord.getWarehouseId())) {
            unlockWarehouseIfNeeded(StoreStockRecordVo.builder()
                    .warehouseId(storeStockRecord.getWarehouseId())
                    .build());
        }
    }

    @Override
    @Transactional
    public void deleteByIdList(List<Long> idList) {
        if (CollectionUtil.isEmpty(idList)) {
            return;
        }
        for (Long id : idList) {
            deleteById(id);
        }
    }

    @Override
    public Long insert(StoreStockRecord storeStockRecord) {
        Date now = new Date();
        storeStockRecord.setCreateTime(now);
        storeStockRecord.setUpdateTime(now);
        return mapper.insert(storeStockRecord) > 0 ? storeStockRecord.getId() : 0L;
    }

    @Override
    public Long insertSelective(StoreStockRecord storeStockRecord) {
        Date now = new Date();
        storeStockRecord.setCreateTime(now);
        storeStockRecord.setUpdateTime(now);
        return mapper.insertSelective(storeStockRecord) > 0 ? storeStockRecord.getId() : 0L;
    }

    @Override
    public boolean update(StoreStockRecord storeStockRecord) {
        Date now = new Date();
        if (BeanUtil.isEmpty(storeStockRecord.getCreateTime()))
            storeStockRecord.setCreateTime(now);
        storeStockRecord.setUpdateTime(now);
        return mapper.updateByPrimaryKey(storeStockRecord) != 0;
    }

    @Override
    public boolean updateByPrimaryKeySelective(StoreStockRecord record) {
        Date now = new Date();
        record.setUpdateTime(now);
        return mapper.updateByPrimaryKeySelective(record) != 0;
    }

    @Override
    @Transactional
    public boolean save(StoreStockRecordSaveOrUpdateVo saveOrUpdateVo) {
        StoreStockRecord storeStockRecord = new StoreStockRecord();
        BeanUtils.copyProperties(saveOrUpdateVo, storeStockRecord);
        if (BeanUtil.isNotEmpty(storeStockRecord.getId()))
            return this.modify(saveOrUpdateVo);
        storeStockRecord.setNumber(createNextNumber());
        if (BeanUtil.isEmpty(saveOrUpdateVo.getStatus()))
            storeStockRecord.setStatus(StoreEnum.StatusEnum.WAIT_APPROVE.getCode().byteValue());
        storeStockRecord.setFoundTime(DateUtil.formatDate(new Date()));
        //先保存入库单
        Long storeRecordId = this.insertSelective(storeStockRecord);
        saveOrUpdateVo.setId(storeRecordId);
        //产品信息
        List<StoreStockRecordProductSaveOrUpdateVo> storeRecordProductList = saveOrUpdateVo.getStoreStockRecordProductList();
        if (BeanUtil.isNotEmpty(storeRecordProductList))
            for (StoreStockRecordProductSaveOrUpdateVo productSaveOrUpdateVo : storeRecordProductList) {
                //循环保存
                productSaveOrUpdateVo.setWarehouseId(saveOrUpdateVo.getWarehouseId());
                productSaveOrUpdateVo.setStoreStockRecordId(storeRecordId);
                storeStockRecordProductService.save(productSaveOrUpdateVo);
            }
        return storeRecordId != 0;
    }

    private BigDecimal getCurrentStoreCount(Map<Long, List<Store>> stockCollect, Long productId) {
        List<Store> stores = stockCollect.get(productId);
        if (stores != null && !stores.isEmpty()) {
            return stores.get(0).getProductCount(); // 返回当前库存数量
        }
        return BigDecimal.ZERO; // 如果没有找到当前库存，返回 0
    }


    @Override
    @Transactional
    public boolean modify(StoreStockRecordSaveOrUpdateVo saveOrUpdateVo) {
        if (BeanUtil.isEmpty(saveOrUpdateVo.getId()))
            return this.save(saveOrUpdateVo);
        StoreStockRecord old = this.selectById(saveOrUpdateVo.getId());
        AssertCommonUtil.notNull(old, "此数据不存在或者已被删除");
        StoreStockRecord storeStockRecord = new StoreStockRecord();
        BeanUtils.copyProperties(saveOrUpdateVo, storeStockRecord);
        if (BeanUtil.isEmpty(storeStockRecord.getStatus()))
            storeStockRecord.setStatus(StoreEnum.StatusEnum.DRAFT.getCode().byteValue());
        if (BeanUtil.isEmpty(storeStockRecord.getStockType()))
            storeStockRecord.setStockType(StoreEnum.STOCK_STATUS_TYPE.DRAFT.getCode());
        this.update(storeStockRecord);
        updateProduct(storeStockRecord, saveOrUpdateVo.getStoreStockRecordProductList());
        return true;
    }

    private void updateProduct(StoreStockRecord storeStockRecord, List<StoreStockRecordProductSaveOrUpdateVo> saveOrUpdateVos) {
        //根据id删除
        storeStockRecordProductService.deleteByCondition(StoreStockRecordProductSearchVo.builder()
                .storeStockRecordId(storeStockRecord.getId())
                .build());
        if (BeanUtil.isNotEmpty(saveOrUpdateVos))
            for (StoreStockRecordProductSaveOrUpdateVo productSaveOrUpdateVo : saveOrUpdateVos) {
                productSaveOrUpdateVo.setWarehouseId(storeStockRecord.getWarehouseId());
                productSaveOrUpdateVo.setStoreStockRecordId(storeStockRecord.getId());
                storeStockRecordProductService.save(productSaveOrUpdateVo);
            }
    }


    @Override
    public StoreStockRecordVo selectOne(StoreStockRecordSearchVo storeStockRecordSearchVo) {
        return mapper.selectOne(storeStockRecordSearchVo);
    }

    @Override
    public Integer count(StoreStockRecordSearchVo storeStockRecordSearchVo) {
        setAppStatusList(storeStockRecordSearchVo);
        return mapper.count(storeStockRecordSearchVo);
    }

    @Override
    public List<StoreStockRecordVo> selectList(StoreStockRecordSearchVo storeStockRecordSearchVo) {
        setAppStatusList(storeStockRecordSearchVo);
        return mapper.selectList(storeStockRecordSearchVo);
    }

    private void setAppStatusList(StoreStockRecordSearchVo storeRecordSearchVo) {
        List<Byte> list = new ArrayList<>();
        if (storeRecordSearchVo.getAppStatus() != null) {
            if (storeRecordSearchVo.getAppStatus() == 0) {
                list = Arrays.asList(
                        StoreEnum.StatusEnum.END.getCode().byteValue(),
                        StoreEnum.StatusEnum.WAIT_APPROVE.getCode().byteValue()
                );
            } else if (storeRecordSearchVo.getAppStatus() == 1) {
                list = Collections.singletonList(StoreEnum.StatusEnum.WAIT_APPROVE.getCode().byteValue());
            } else if (storeRecordSearchVo.getAppStatus() == 2) {
                list = Collections.singletonList(StoreEnum.StatusEnum.END.getCode().byteValue());
            }
        }
        storeRecordSearchVo.setAppStatusList(list);
    }

    @Override
    public Page<StoreStockRecordVo> selectPage(StoreStockRecordSearchVo storeStockRecordSearchVo) {
        AssertCommonUtil.check(
                Objects.isNull(storeStockRecordSearchVo.getPageNum())
                        || Objects.isNull(storeStockRecordSearchVo.getPageSize()),
                "分页参数不能为空");
        // 先直接查总数
        int count = count(storeStockRecordSearchVo);
        // 分页
        Page<StoreStockRecordVo> page =
                new Page<>(
                        true,
                        count,
                        storeStockRecordSearchVo.getPageNum(),
                        storeStockRecordSearchVo.getPageSize());
        storeStockRecordSearchVo.setStartIndex(page.getStartIndex());
        page.setPage(true);
        page.setTotalCount(count);
        List<StoreStockRecordVo> responseVos = this.selectList(storeStockRecordSearchVo);
        page.setData(responseVos);
        return page;
    }

    @Override
    public boolean insertBatch(List<StoreStockRecord> entities) {
        return CollectionUtil.isNotEmpty(entities) && mapper.insertBatch(entities) > 0;
    }

    @Override
    public String selectMaxNumber() {
        return mapper.selectMaxNumberByDay(DateUtil.formatDate(new Date()));
    }

    @Override
    public String createNextNumber() {
        String maxCode = this.selectMaxNumber();
        if (StringUtils.isBlank(maxCode)) {
            return String.format("%s-%s-001", CodingEnum.PREFIX.PD.value, DateUtil.format(new Date(), FastDateFormat.getInstance("yyyyMMdd")));
        }
        String[] maxCodeArray = maxCode.split("-");
        Integer i = Integer.valueOf(maxCodeArray[maxCodeArray.length - 1]);
        i++;
        return String.format("%s-%s-%s", CodingEnum.PREFIX.PD.value, DateUtil.format(new Date(), FastDateFormat.getInstance("yyyyMMdd")), String.format("%03d", i));
    }

    @Override
    @Transactional
    public boolean submitStock(StoreStockRecordSaveOrUpdateVo param) {
        storeLockService.updateLock(StoreLockSaveOrUpdateVo.builder()
                .warehouseId(param.getWarehouseId())
                .type(param.getWarehouseLockStatus())
                .build());
        List<StoreStockRecordProductSaveOrUpdateVo> storeStockRecordProductList = param.getStoreStockRecordProductList();
        AssertCommonUtil.check(BeanUtil.isEmpty(storeStockRecordProductList), "盘点单不存在或无产品信息");
        storeStockRecordProductList.forEach(vo -> {
            AssertCommonUtil.check(BeanUtil.isEmpty(vo.getWarehouseLocationId()), "产品中库位信息不得为空");
            //AssertCommonUtil.check(BeanUtil.isEmpty(vo.getStockCount()), "产品明细中数量不得为空");
            AssertCommonUtil.check(BeanUtil.isEmpty(vo.getWarehouseId()), "产品明细中仓库不得为空");
        });
        param.setStockType(StoreEnum.STOCK_STATUS_TYPE.WAIT_APPROVE.getCode());
        param.setStatus(StoreEnum.StatusEnum.WAIT_APPROVE.getCode().byteValue());
        return modify(param);
    }

    @Override
    @Transactional
    public boolean auditStock(StoreStockRecordSaveOrUpdateVo param) {
        List<StoreStockRecordProductSaveOrUpdateVo> storeStockRecordProductList = param.getStoreStockRecordProductList();
        AssertCommonUtil.check(BeanUtil.isEmpty(storeStockRecordProductList), "盘点单不存在或无产品信息");
        storeStockRecordProductList.forEach(vo -> {
            AssertCommonUtil.check(BeanUtil.isEmpty(vo.getWarehouseLocationId()), "产品中库位信息不得为空");
            AssertCommonUtil.check(BeanUtil.isEmpty(vo.getStockCount()), "产品明细中数量不得为空");
            AssertCommonUtil.check(BeanUtil.isEmpty(vo.getWarehouseId()), "产品明细中仓库不得为空");
        });
        modify(param);
        StoreStockRecord storeStockRecord = this.selectById(param.getId());
        AssertCommonUtil.check(BeanUtil.isEmpty(storeStockRecord), "盘点单不存在");
        AssertCommonUtil.check(!storeStockRecord.getStockType().equals(StoreEnum.STOCK_STATUS_TYPE.WAIT_APPROVE.getCode()), "非盘点中状态，不能提交审核，请先提交盘点");
        Set<Long> warehouseIds = param.getStoreStockRecordProductList().stream().map(StoreStockRecordProductSaveOrUpdateVo::getWarehouseId).collect(Collectors.toSet());
        warehouseIds.forEach(p -> {
            StoreLockVo storeLock = storeLockService.selectByWarehouseId(p);
            AssertCommonUtil.check(Objects.equals(storeLock.getType(), StoreEnum.LOCK_TYPE.UNLOCKED.getCode()), String.format("仓库%s未锁定，无法提交盘点", storeLock.getWarehouseName()));
        });
        this.updateByPrimaryKeySelective(StoreStockRecord.builder().id(param.getId())
                .stockType(StoreEnum.STOCK_STATUS_TYPE.STOCK_CHECKING.getCode()) // 待亏盈处理
                .status(Byte.valueOf(String.valueOf(StoreEnum.StatusEnum.END.getCode()))) //提交审核即为审核通过
                .build());
        //拆分单据
        this.resolution(this.selectVoById(param.getId()));
        return true;
    }

    @Override
    public StoreStockRecordVo selectVoByNumber(String number) {
        StoreStockRecordVo storeStockRecordVo = this.selectOne(StoreStockRecordSearchVo.builder().number(number).build());
        AssertCommonUtil.check(BeanUtil.isEmpty(storeStockRecordVo), "盈亏单不存在");
        return selectVoById(storeStockRecordVo.getId());
    }

    @Override
    @Transactional
    public boolean monadAuditStock(StoreStockRecordSaveOrUpdateVo param, int sourceType) {
        // 根据ID查询库存记录
        StoreStockRecordVo storeStockRecordVo = this.selectVoById(param.getId());
        // 进行初步检查，确保盘点记录可以审核
        checkPreconditions(storeStockRecordVo, param);
        // 本单 设置状态为结束
        param.setStockType(StoreEnum.STOCK_STATUS_TYPE.END.getCode());
        //更新基础数据
        this.updateByPrimaryKeySelective(StoreStockRecord.builder()
                .id(param.getId())
                .stockType(StoreEnum.STOCK_STATUS_TYPE.END.getCode())
                .build());
        //更新产品信息详情
        updateProduct(this.selectById(param.getId()), param.getStoreStockRecordProductList());
        // 收集库存变更信息
        List<StockStorageDto> stockStorages = gatherStockStorageUpdates(param);
        // 创建库存操作DTO
        StockActionDto action = createStockAction(param, storeStockRecordVo, stockStorages, sourceType);
        // 执行库存操作
        storeService.stockAction(action);
        // 处理与本次操作相关的单据
        StoreStockRecordVo originalRecord = handleRelatedRecords(storeStockRecordVo);
        // 如果有原始单据，则判断是否完成盘点
        completeAuditIfNeeded(originalRecord,storeStockRecordVo.getStoreStockRecordId());
        // 检查是否需要解锁仓库
        unlockWarehouseIfNeeded(storeStockRecordVo);
        return true;
    }

    // 检查初始条件的方法，确保盘点状态可以继续审核
    private void checkPreconditions(StoreStockRecordVo storeStockRecordVo, StoreStockRecordSaveOrUpdateVo param) {
        // 检查是否已经完成盘点
        AssertCommonUtil.check(storeStockRecordVo.getStockType() == StoreEnum.STOCK_STATUS_TYPE.END.getCode().byteValue(), "盘点单已完成，无法再次盘点");
        // 检查盘点记录是否存在产品信息
        AssertCommonUtil.check(BeanUtil.isEmpty(param.getStoreStockRecordProductList()), "盘点单不存在或无产品信息");
        // 检查当前状态是否允许审核
        AssertCommonUtil.check(storeStockRecordVo.getStockType() != StoreEnum.STOCK_STATUS_TYPE.STOCK_CHECKING.getCode().byteValue(),
                "仅允许待盘盈亏单子审核");
    }

    // 收集库存变更信息
    private List<StockStorageDto> gatherStockStorageUpdates(StoreStockRecordSaveOrUpdateVo param) {
        List<StockStorageDto> stockStorages = new ArrayList<>();
        // 遍历产品列表，构建库存变更DTO
        StoreStockRecordVo storeStockRecordVo = this.selectVoById(param.getId());
        List<StoreStockRecordProductVo> dets = storeStockRecordVo.getStoreStockRecordProductList();
        dets.forEach(p -> {
            //查询库存
            StoreVo storeVo = storeService.selectOne(StoreSearchVo.builder().productId(p.getProductId()).warehouseLocationId(p.getWarehouseLocationId()).build());
            BigDecimal storeCount = storeVo == null ? BigDecimal.ZERO : storeVo.getProductCount();
            stockStorages.add(StockStorageDto.builder()
                    .productId(p.getProductId())
                    .warehouseId(p.getWarehouseId())
                    .warehouseLocationId(p.getWarehouseLocationId())
                    .count(p.getStockCount().subtract(storeCount).abs())
                    .build());
        });
        return stockStorages;
    }

    // 创建库存操作DTO
    private StockActionDto createStockAction(StoreStockRecordSaveOrUpdateVo param, StoreStockRecordVo storeStockRecordVo, List<StockStorageDto> stockStorages, int sourceType) {
        // 依据盘点记录的类型设定操作类型
        StockActionEnum.ACTION_TYPE actionType = storeStockRecordVo.getType().equals(StoreEnum.STOCK_TYPE.LOST.getCode())
                ? StockActionEnum.ACTION_TYPE.CHECK_OUT
                : StockActionEnum.ACTION_TYPE.CHECK_IN;

        return StockActionDto.builder()
                .actionType(actionType)
                .stockStorages(stockStorages)
                .voucherCode(storeStockRecordVo.getNumber())
                .optId(storeStockRecordVo.getId())
                .optSource(sourceType)
                .voucherTime(com.zhijian.util.DateUtil.getTime(com.zhijian.util.DateUtil.DATE_FORMAT))
                .optUserId(param.getUpdateUserId())
                .crtUserId(storeStockRecordVo.getCreateUserId())
                .build();
    }

    // 处理与当前单据相关的单据
    private StoreStockRecordVo handleRelatedRecords(StoreStockRecordVo storeStockRecordVo) {
        StoreStockRecordSearchVo storeStockRecordCriteria = new StoreStockRecordSearchVo();
        // 根据损失号或收益号查询相关单据
        if (storeStockRecordVo.getType().equals(StoreEnum.STOCK_TYPE.LOST.getCode())) {
            storeStockRecordCriteria.setLossesNumber(storeStockRecordVo.getNumber());
        } else {
            storeStockRecordCriteria.setProfitNumber(storeStockRecordVo.getNumber());
        }
        // 返回找到的原始单据
        if (BeanUtil.isEmpty(storeStockRecordCriteria.getProfitNumber()) && BeanUtil.isEmpty(storeStockRecordCriteria.getLossesNumber()))
            return null;
        StoreStockRecordVo storeStockRecordVo1 = this.selectOne(storeStockRecordCriteria);
        if (BeanUtil.isNotEmpty(storeStockRecordVo1)) {
            storeStockRecordVo.setStoreStockRecordId(storeStockRecordVo1.getId());
            StoreStockRecordVo storeStockRecordVo2 = null;
            if (storeStockRecordVo.getType().equals(StoreEnum.STOCK_TYPE.LOST.getCode()) && BeanUtil.isNotEmpty(storeStockRecordVo1.getProfitNumber())) {
                storeStockRecordVo2 = selectVoByNumber(storeStockRecordVo1.getProfitNumber());
            } else if (storeStockRecordVo.getType().equals(StoreEnum.STOCK_TYPE.PROFIT.getCode())&&BeanUtil.isNotEmpty(storeStockRecordVo1.getLossesNumber())) {
                storeStockRecordVo2 = selectVoByNumber(storeStockRecordVo1.getLossesNumber());
            }
            return storeStockRecordVo2;
        }
        return null;
    }

    // 根据相关记录判断是否完成审核
    private void completeAuditIfNeeded(StoreStockRecordVo originalRecord,Long storeStockRecordId) {
        // 查询与原始记录关联的单据
        // StoreStockRecordVo storeStockRecordRelevance = findRelevanceRecord(originalRecord);
        // 若关联记录为空或状态为结束，则标记原始单据为完成
        if (BeanUtil.isEmpty(originalRecord) ||
                (originalRecord.getStockType() == StoreEnum.STOCK_STATUS_TYPE.END.getCode().byteValue())) {
            this.updateByPrimaryKeySelective(StoreStockRecord.builder()
                    .id(storeStockRecordId)
                    .stockType(StoreEnum.STOCK_STATUS_TYPE.END.getCode())
                    .build());
        }
    }

    // 查找与原始记录关联的单据
    private StoreStockRecordVo findRelevanceRecord(StoreStockRecordVo originalRecord) {
        StoreStockRecordSearchVo storeStockRecordLossSearchVo = new StoreStockRecordSearchVo();
        // 根据单据类型设置查询条件
        if (originalRecord.getType().equals(StoreEnum.STOCK_TYPE.LOST.getCode())) {
            storeStockRecordLossSearchVo.setProfitNumber(originalRecord.getProfitNumber());
        } else {
            storeStockRecordLossSearchVo.setLossesNumber(originalRecord.getLossesNumber());
        }

        // 如果收益号或损失号不为空，则查询相关记录
        if (BeanUtil.isNotEmpty(storeStockRecordLossSearchVo.getProfitNumber()) ||
                BeanUtil.isNotEmpty(storeStockRecordLossSearchVo.getLossesNumber())) {
            return this.selectOne(storeStockRecordLossSearchVo);
        }
        return null; // 如果没有找到记录，返回null
    }

    // 检查是否需要解锁仓库
    private void unlockWarehouseIfNeeded(StoreStockRecordVo originalRecord) {
        // 查询当前仓库未完成单据的数量
        Integer count = this.count(StoreStockRecordSearchVo.builder()
                .warehouseId(originalRecord.getWarehouseId())
                .stockTypes(Arrays.asList(StoreEnum.STOCK_STATUS_TYPE.STOCK_CHECKING.getCode(), StoreEnum.STOCK_STATUS_TYPE.WAIT_APPROVE.getCode()))
                .build());

        // 如果未完成的单子数量为0，则解锁该仓库
        if (count == 0) {
            StoreLockVo storeLock = storeLockService.selectByWarehouseId(originalRecord.getWarehouseId());
            storeLockService.updateByPrimaryKeySelective(StoreLock.builder()
                    .id(storeLock.getId())
                    .type(StoreEnum.LOCK_TYPE.UNLOCKED.getCode())
                    .build());
        }
    }


    /**
     * 根据盘点记录的产品，确定需要拆分的数据及新创建的盘点单据类型
     *
     * @param saveOrUpdateVo
     * @return
     */
    private boolean resolution(StoreStockRecordVo saveOrUpdateVo) {
        // 检查产品列表是否为空
        AssertCommonUtil.notNull(saveOrUpdateVo.getStoreStockRecordProductList(), "产品列表不能为空");

        // 根据库位分组盘点产品
        Map<Long, List<StoreStockRecordProductVo>> locationGroups =
                saveOrUpdateVo.getStoreStockRecordProductList().stream()
                        .collect(Collectors.groupingBy(StoreStockRecordProductVo::getWarehouseLocationId));
        // 根据库位id查询库存
        List<Long> productIds = saveOrUpdateVo.getStoreStockRecordProductList().stream()
                .map(StoreStockRecordProductVo::getProductId).collect(Collectors.toList());
        Map<Long, List<Store>> stockCollect = getCurrentStock(saveOrUpdateVo.getWarehouseId(), locationGroups.keySet(), productIds);
        // 根据盈亏类型分组盘点记录
        Map<Integer, StoreStockRecord> recordMap = new HashMap<>();
        // 盘点的产品
        for (Map.Entry<Long, List<StoreStockRecordProductVo>> locationListEntry : locationGroups.entrySet()) {
            //盘点的产品
            Map<Long, List<StoreStockRecordProductVo>> productListEntry = locationListEntry.getValue().stream().collect(Collectors.groupingBy(StoreStockRecordProductVo::getProductId));
            //如果存在
            if (stockCollect.containsKey(locationListEntry.getKey())) {
                //库存
                Map<Long, List<Store>> storeProductCollect = stockCollect.get(locationListEntry.getKey()).stream().collect(Collectors.groupingBy(Store::getProductId));
                productListEntry.entrySet().forEach(entry -> {
                    // 盘点的库存
                    BigDecimal totalStockCount = calculateTotalStockCount(entry);
                    int type = determineRecordType(storeProductCollect, entry.getKey(), totalStockCount);
                    if (storeProductCollect.containsKey(entry.getKey())) {
                        // 盘平单不生成盘点记录
                        if (type != StoreEnum.STOCK_TYPE.BALANCE.getCode()) {
                            //库存与盘点差数量
                            //BigDecimal stockCountSum = calculateStockCountSum(storeProductCollect, entry.getKey(), totalStockCount).abs();
                            // 设置数据
                            addProduct(entry.getValue().get(0), getCurrentStoreCount(storeProductCollect, entry.getKey()), totalStockCount,
                                    recordMap, type, saveOrUpdateVo);
                        }
                    } else {
                        // 设置数据
                        addProduct(entry.getValue().get(0), BigDecimal.ZERO, calculateTotalStockCount(entry),
                                recordMap, type, saveOrUpdateVo);
                    }
                });
            }
            //如果不存在则全部新增
            else {
                productListEntry.entrySet().forEach(entry -> {
                    // 设置数据
                    addProduct(entry.getValue().get(0), BigDecimal.ZERO, calculateTotalStockCount(entry),
                            recordMap, StoreEnum.STOCK_TYPE.PROFIT.getCode(), saveOrUpdateVo);
                });
            }
        }
        // 保存盘点记录
        if (!recordMap.isEmpty()) {
            saveStockRecords(recordMap, saveOrUpdateVo);
        } else {
            //如果没有亏盈单 则直接盘点完成
            this.updateByPrimaryKeySelective(StoreStockRecord.builder()
                    .stockType(StoreEnum.STOCK_STATUS_TYPE.END.getCode())
                    .id(saveOrUpdateVo.getId())
                    .build());
            //解锁仓库
            unlockWarehouseIfNeeded(StoreStockRecordVo.builder()
                    .warehouseId(saveOrUpdateVo.getWarehouseId())
                    .build());
        }
        return true;
    }

    /**
     * 新增产品
     *
     * @param productSaveOrUpdateVo 产品保存对象
     * @param currentStoreCount     当前库存数量
     * @param stockCountSum         盘点数量
     * @param recordMap             盘点记录集合
     * @param type                  盘点类型
     * @param saveOrUpdateVo        盘点记录保存对象
     */
    private void addProduct(StoreStockRecordProductVo productSaveOrUpdateVo, BigDecimal currentStoreCount, BigDecimal stockCountSum, Map<Integer, StoreStockRecord> recordMap, int type, StoreStockRecordVo saveOrUpdateVo) {
        productSaveOrUpdateVo.setStockCount(stockCountSum); // 盘点数量
        productSaveOrUpdateVo.setStoreCount(currentStoreCount); // 当前库存数量
        productSaveOrUpdateVo.setWarehouseId(saveOrUpdateVo.getWarehouseId());
        StoreStockRecord storeStockRecord = recordMap.computeIfAbsent(type, k -> createNewStoreStockRecord(saveOrUpdateVo, type));
        storeStockRecord.addProduct(productSaveOrUpdateVo);
    }

    /**
     * 查询仓库当前库存 并根据库位id分组
     *
     * @param warehouseId          仓库ID
     * @param warehouseLocationIds 产品ID集合
     * @return 仓库当前库存
     */
    private Map<Long, List<Store>> getCurrentStock(Long warehouseId, Set<Long> warehouseLocationIds, List<Long> productIds) {
        List<Store> stocks = storeService.selectByCommodityIds(warehouseId, new ArrayList<>(warehouseLocationIds), productIds);
        return BeanUtil.isNotEmpty(stocks) ?
                stocks.stream().collect(Collectors.groupingBy(Store::getWarehouseLocationId)) :
                new HashMap<>();
    }

    /**
     * 计算各产品的盘点数量（主要是为了去重）
     *
     * @param productListEntry 产品列表
     * @return 各产品的库存记录
     */
    private BigDecimal calculateTotalStockCount(Map.Entry<Long, List<StoreStockRecordProductVo>> productListEntry) {
        return productListEntry.getValue().stream()
                .map(StoreStockRecordProductVo::getStockCount)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
    }

    /**
     * 根据盈亏类型确定盘点记录类型
     *
     * @param stockCollect    仓库当前库存
     * @param productId       产品ID
     * @param totalStockCount 各产品的盘点数量
     * @return 盘点记录类型
     */
    private int determineRecordType(Map<Long, List<Store>> stockCollect, Long productId, BigDecimal totalStockCount) {
        if (BeanUtil.isEmpty(stockCollect.get(productId))) {
            return StoreEnum.STOCK_TYPE.PROFIT.getCode();
        } else {
            Store store = stockCollect.get(productId).get(0);
            if (store.getProductCount().compareTo(totalStockCount) < 0) {
                return StoreEnum.STOCK_TYPE.PROFIT.getCode();
            } else if (store.getProductCount().compareTo(totalStockCount) > 0) {
                return StoreEnum.STOCK_TYPE.LOST.getCode();
            }
        }
        return StoreEnum.STOCK_TYPE.BALANCE.getCode();
    }

    /**
     * 计算各产品的盘点数量（主要是为了去重）
     *
     * @param stockCollect    仓库当前库存
     * @param productId       产品ID
     * @param totalStockCount 各产品的盘点数量
     * @return 各产品的库存记录
     */
    private BigDecimal calculateStockCountSum(Map<Long, List<Store>> stockCollect, Long productId, BigDecimal totalStockCount) {
        if (BeanUtil.isEmpty(stockCollect.get(productId))) {
            return totalStockCount;
        } else {
            Store store = stockCollect.get(productId).get(0);
            return store.getProductCount().subtract(totalStockCount); // 当前库存数量减去盘点数量
        }
    }

    /**
     * 创建新的盘点记录
     *
     * @param saveOrUpdateVo 盘点记录保存对象
     * @param type           盘点类型
     * @return 新的盘点记录
     */
    private StoreStockRecord createNewStoreStockRecord(StoreStockRecordVo saveOrUpdateVo, int type) {
        StoreStockRecord newRecord = new StoreStockRecord();
        BeanUtils.copyProperties(saveOrUpdateVo, newRecord);
        newRecord.setStoreStockRecordProductList(null);
        newRecord.setType(type);
        return newRecord;
    }

    /**
     * 保存盘点记录
     *
     * @param recordMap 盘点记录集合
     */
    private void saveStockRecords(Map<Integer, StoreStockRecord> recordMap, StoreStockRecordVo saveOrUpdateVo) {
        for (StoreStockRecord stockRecord : recordMap.values()) {
            stockRecord.setNumber(createNextNumber());
            if (stockRecord.getType().equals(StoreEnum.STOCK_TYPE.PROFIT.getCode())) {
                saveOrUpdateVo.setProfitNumber(stockRecord.getNumber());
            } else if (stockRecord.getType().equals(StoreEnum.STOCK_TYPE.LOST.getCode())) {
                saveOrUpdateVo.setLossesNumber(stockRecord.getNumber());
            }
            //如果是盘平单 并且提交审核  自动通过审核
            if (stockRecord.getType().equals(StoreEnum.STOCK_TYPE.BALANCE.getCode()) && Integer.valueOf(stockRecord.getStatus()).equals(StoreEnum.STOCK_STATUS_TYPE.WAIT_APPROVE.getCode()))
                stockRecord.setStatus(Byte.valueOf(String.valueOf(StoreEnum.STOCK_STATUS_TYPE.WAIT_APPROVE.getCode())));
            Long stockRecordId = this.insertSelective(stockRecord);
            for (StoreStockRecordProductVo product : stockRecord.getStoreStockRecordProductList()) {
                product.setStoreStockRecordId(stockRecordId);
                storeStockRecordProductService.saveByVo(product);
            }
        }
        //更新单据单号
        this.updateByPrimaryKeySelective(StoreStockRecord.builder()
                .id(saveOrUpdateVo.getId()).profitNumber(saveOrUpdateVo.getProfitNumber() == null ? "" : saveOrUpdateVo.getProfitNumber())
                .lossesNumber(saveOrUpdateVo.getLossesNumber() == null ? "" : saveOrUpdateVo.getLossesNumber()).build());
    }
}


